#pragma once

#include "DXTypeDefs.h"
#include "BufferManager.h"

namespace Rendering {

	///<summary>Topology for the rendering.</summary>
	typedef enum RenderTopology
	{
		///<summary>Triangle list topology.</summary>
		TriangleList,
		///<summary>Line list topology.</summary>
		LineList,
		///<summary>Triangle strip topology.</summary>
		TriangleStrip
	};

	class Renderer;

class Mesh
{
public:
	virtual void Render(_In_ Renderer* renderer) = 0;
	static D3D_PRIMITIVE_TOPOLOGY RenderToplogyToD3DPrimitiveTopology(RenderTopology renderTopology);

	/// <summary>Creates a vertex buffer and saves it into this object.</summary>
	/// <param name="device">The direct3d device.</param>
	/// <param name="vertexCount">The number of vertices for a mesh.</param>
	/// <param name="vertices">The vertices.</param>
template<class U>				
	void SetVertices(_In_ ID3D11Device *device, _In_ unsigned int vertexCount, _In_reads_(vertexCount) U* vertices)
	{
		this->VertexCount = vertexCount;
		BufferManager::CreateVertexBuffer(device, this->VertexCount, vertices, &m_vertexBuffer);
	}

	void SetIndices(_In_ ID3D11Device *device, _In_ unsigned int indexCount,  _In_reads_(indexCount) unsigned short* indices);
		
	///<summary>Gets/Sets the vertex count for this mesh.</summary>
	///<value>The vertex count.</value>
	int VertexCount;

	///<summary>Gets/Sets the index count for this mesh.</summary>
	///<value>The index count.</value>
	int IndexCount;

	///<summary>Gets/Sets the topology count for this mesh.</summary>
	///<value>The render topology.</value>
	RenderTopology Topology;

protected:
	ID3D11BufferPtr  m_vertexBuffer;
	ID3D11BufferPtr  m_indexBuffer;
};

///<summary>A mesh definition templated for vertex.</summary>
template<class T>
	class GenericMesh : public Mesh
	{
	public:
		/// <summary>Constructor creating vertex and index buffers.</summary>
		/// <param name="device">The direct3d device.</param>
		/// <param name="vertexCount">The number of vertices for a mesh.</param>
		/// <param name="vertices">The vertices.</param>
		/// <param name="indexCount">The number of indices for a mesh.</param>
		/// <param name="indices">The indices.</param>
		GenericMesh(_In_ ID3D11Device *device, _In_ unsigned int vertexCount, _In_reads_(vertexCount) T vertices[], _In_ unsigned int indexCount,  _In_reads_(indexCount) unsigned short* indices)
		{
			this->Topology = RenderTopology::TriangleList;
			SetVertices(device, vertexCount, vertices);
			SetIndices(device, indexCount, indices);
		}

		/// <summary>Renders the object.</summary>
		/// <param name="renderer">The renderer to render this object.</param>
		virtual void Render(_In_ Renderer* renderer) override
		{
			UINT stride = sizeof(T);
			UINT offset = 0;

			ID3D11DeviceContext1Ptr context = renderer->Context();
			context->IASetVertexBuffers(0, 1, &m_vertexBuffer.GetInterfacePtr(), &stride, &offset);
			context->IASetPrimitiveTopology(RenderToplogyToD3DPrimitiveTopology(this->Topology));
			if (m_indexBuffer != nullptr)
			{
				context->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R16_UINT, 0);
				context->DrawIndexed(this->IndexCount, 0, 0);
			}
			else
			{
				context->Draw(this->VertexCount, 0);
			}
		}
	};
}